package net.nohaven.proj.javeau.fs;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import net.nohaven.proj.javeau.fs.exceptions.ConditionsNotMetException;
import net.nohaven.proj.javeau.fs.exceptions.EntityAlreadyPresentException;
import net.nohaven.proj.javeau.fs.exceptions.EntityNotFoundException;
import net.nohaven.proj.javeau.fs.exceptions.GenericIOException;
import net.nohaven.proj.javeau.fs.hybrid.HFilesystem;
import net.nohaven.proj.javeau.fs.model.FSDirectory;
import net.nohaven.proj.javeau.fs.model.FSFile;
import net.nohaven.proj.javeau.fs.model.FSFileWriter;
import net.nohaven.proj.javeau.fs.model.FSItem;
import net.nohaven.proj.javeau.fs.model.Filesystem;
import net.nohaven.proj.javeau.utils.Utils;

public class FSUtils {
	public static final boolean isDir(FSItem i) {
		return i instanceof FSDirectory;
	}

	public static final boolean isFile(FSItem i) {
		return i instanceof FSFile;
	}

	private static final String[] MAGNITUDE = new String[] { " b", " k", " M",
			" G" };

	public static String getSizeString(FSItem item) {
		FSFile file = (FSFile) item;
		long size = file.getSize();
		int mag = 0;

		while (size >= 1024) {
			size /= 1024;
			mag++;
		}

		return Long.toString(size) + MAGNITUDE[mag];
	}

	public static void deleteRecursive(Filesystem fs, String name)
			throws ConditionsNotMetException {
		FSItem item = fs.get(name);
		if (item == null || "..".equals(item.getName()))
			return;

		if (isDir(item)) {
			//recursion
			try {
				if (fs instanceof HFilesystem)
					((HFilesystem) fs).cdNoSwap(name);
				else
					fs.cd(name);
			} catch (EntityNotFoundException e) {
				// impossible
			}
			FSItem[] list = fs.ls();
			for (FSItem it : list)
				deleteRecursive(fs, it.getName());
			fs.cdUp();
		}
		fs.delete(name);
	}

	private static void copyFile(Filesystem fs, Filesystem otherFS, String name)
			throws EntityNotFoundException, EntityAlreadyPresentException,
			GenericIOException {
		FSItem asrc = fs.get(name);
		FSFile src = (FSFile) asrc;
		FSFileWriter dest = otherFS.createFile(name);

		InputStream is = src.getContent();
		OutputStream os = dest.getOutputStream();

		try {
			Utils.copy(is, os);
			os.flush();
			is.close();
			dest.commit();
		} catch (IOException e) {
			try {
				os.close();
				dest.abort();
			} catch (Exception e2) {
			}
			throw new GenericIOException(e.getMessage(), e);
		}
	}

	public static void copyRecursive(Filesystem fs, Filesystem otherFS,
			String name) throws EntityNotFoundException,
			EntityAlreadyPresentException, GenericIOException {
		FSItem item = fs.get(name);
		if (item == null || "..".equals(item.getName()))
			return;

		if (isDir(item)) {
			//recursion
			try {
				otherFS.mkDir(name);

				if (fs instanceof HFilesystem)
					((HFilesystem) fs).cdNoSwap(name);
				else
					fs.cd(name);

				if (otherFS instanceof HFilesystem)
					((HFilesystem) otherFS).cdNoSwap(name);
				else
					otherFS.cd(name);
			} catch (EntityNotFoundException e) {
				// impossible
			}
			FSItem[] list = fs.ls();
			for (FSItem it : list)
				if (isDir(it))
					copyRecursive(fs, otherFS, it.getName());
				else
					copyFile(fs, otherFS, it.getName());
			fs.cdUp();
			otherFS.cdUp();
		} else
			copyFile(fs, otherFS, name);
	}

	public static void move(Filesystem fs, Filesystem otherFS, String name)
			throws EntityNotFoundException, EntityAlreadyPresentException,
			GenericIOException {
		copyRecursive(fs, otherFS, name);
		try {
			deleteRecursive(fs, name);
		} catch (ConditionsNotMetException e) {
			//impossible
		}
	}

}
